
#ifndef __RSP_CLASSDEF__HEADER_FILE__
#define __RSP_CLASSDEF__HEADER_FILE__


//#include "coid/comm/binstream/circularstreambuf.h"
#include "coid/comm/str.h"
#include "coid/comm/hash/hashkeyset.h"
#include "rsp_def.h"


////////////////////////////////////////////////////////////////////////////////
///Class definition container object, implicitly replicated in the RSP
/**
    An instance of this class is always replicated as the first object in the
    replication set. It defines a class name table, a table that contains names
    of classes that can be replicated. The number referring to their position 
    within the table is used as the class identifier during the replication.
**/
template <class T>
class rsp_classdef : public rsp_base
{
protected:
    struct def
    {
        T _data;
        charstr _name;

        def( const token& name, const T& data ) : _data(data),_name(name)  { }

        operator const charstr& () const    { return _name; }
    };

    dynarray<def*>   _classreg;             ///< registered class names
    hash_keyset< token,def*,_Select_GetRefPtr<def,charstr> > _hash;

public:

    rsp_classdef()
    {
    }

    token class_name() const
    {
        static token _t = "$rsp_classdef";
        return _t;
    }

    void frame()
    {
    }

    void command( uchar cd, binstream& cmd )
    {
    }

    const T* find_class( const token& name ) const
    {
        def* const* pi = _hash.find_value(name);
        if(pi)
            return &(**pi)._data;
        return 0;
    }

    const T& get_class( uint i ) const
    {
        return _classreg[i]->_data;
    }

    token get_class_name( uint i ) const
    {
        DASSERT( i < _classreg.size() );
        DASSERT( !_classreg[i]->_name.is_empty() );
        return _classreg[i]->_name;
    }

    ///Stream rsp_classdef to the binstream
    void stream_out( binstream& bin )
    {
        uints crs = _classreg.size();
        bin << (ushort)crs;
        for( uints i=0; i<crs; ++i )       //stream the diff
            bin << _classreg[i]->_name;
    }

    ///Stream rsp_classdef from the binstream
    void stream_in( binstream& bin )
    {
        ushort crs;
        bin >> crs;
        _classreg.need_new(crs);

        charstr name;
        for( ushort i=0; i<crs; ++i )
        {
            ushort ns;
            bin >> ns;
            bin.xread_raw( name.get_buf(ns), ns );

            def** pd = (def**)_hash.find_value(name);
            RASSERTX( pd!=0, "a class not defined on client" );

            _classreg[i] = *pd;
        }
    }
};


#endif //__RSP_CLASSDEF__HEADER_FILE__
